package com.VitalFit.service.serviceImpl;

import com.VitalFit.model.entity.Appointment;
import com.VitalFit.model.entity.Customer;
import com.VitalFit.model.entity.FitnessPlan;
import com.VitalFit.model.entity.Trainer;
import com.VitalFit.model.enums.FitnessPlanTypeEnum;
import com.VitalFit.model.enums.OrderStateEnum;
import com.VitalFit.exception.AppointmentException;
import com.VitalFit.exception.FitnessPlanException;
import com.VitalFit.mapper.AppointmentMapper;
import com.VitalFit.mapper.FitnessPlanMapper;
import com.VitalFit.model.dto.AppointmentDTO;
import com.VitalFit.model.dto.FitnessPlanDTO;
import com.VitalFit.model.vo.AppointmentVO;
import com.VitalFit.model.vo.FitnessPlanVO;
import com.VitalFit.repository.AppointmentRepository;
import com.VitalFit.repository.FitnessPlanRepository;
import com.VitalFit.repository.UserRepository;
import com.VitalFit.service.CustomerService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.MethodArgumentNotValidException;


@Service
@RequiredArgsConstructor
public class CustomerServiceImpl implements CustomerService {

    private final UserRepository userRepository;

    private final FitnessPlanRepository fitnessPlanRepository;

    private final AppointmentRepository appointmentRepository;

    @Override
    @Transactional(rollbackFor = {MethodArgumentNotValidException.class, AppointmentException.class})
    public AppointmentVO makeAppointment(Long userId, AppointmentDTO appointmentDTO) {
        Customer customer = (Customer) userRepository.findById(userId)
                .orElseThrow(() -> new AppointmentException("Invalid user ID"));

        Trainer trainer = (Trainer) userRepository.findById(appointmentDTO.getTrainerId())
                .orElseThrow(() -> new AppointmentException("Invalid trainer ID"));


        if (fitnessPlanRepository.findFitnessPlanByCustomerAndOrderStateEnum(OrderStateEnum.EXECUTED,customer).isEmpty()){
            throw new AppointmentException("The user must purchase fitness plan first");
        }

        if (!appointmentRepository.findOverlappingAppointments(trainer,appointmentDTO.getStartDateTime(),
                appointmentDTO.getEndDateTime()).isEmpty()) {
            throw new AppointmentException("The trainer is not available now");
        }

        Appointment appointment = AppointmentMapper.INSTANCE.appointmentDTOToAppointment(appointmentDTO,customer,trainer);

        appointmentRepository.save(appointment);

        return AppointmentMapper.INSTANCE.appointmentToAppointmentVO(appointment,trainer);

    }


    
    @Override
    @Transactional(rollbackFor = {MethodArgumentNotValidException.class, FitnessPlanException.class})
    public FitnessPlanVO purchaseFitnessPlan(Long userId, FitnessPlanDTO fitnessPlanDTO) {

        Customer customer = (Customer) userRepository.findById(userId)
                .orElseThrow(() -> new FitnessPlanException("Invalid user ID"));

        if (!fitnessPlanRepository.findFitnessPlanByCustomerAndOrderStateEnum(OrderStateEnum.EXECUTED,customer).isEmpty()){
            throw new FitnessPlanException("The user has already had a fitness plan");
        }

        FitnessPlanTypeEnum fitnessPlanTypeEnum = FitnessPlanTypeEnum.getFitnessPlanByPlanName(fitnessPlanDTO.getPlanType());
        FitnessPlan fitnessPlan  = FitnessPlanMapper.INSTANCE.fitnessPlanDTOToFitnessPlan(fitnessPlanDTO,customer
                ,fitnessPlanTypeEnum, OrderStateEnum.EXECUTED);
        fitnessPlanRepository.save(fitnessPlan);

        return FitnessPlanMapper.INSTANCE.fitnessPlanToFitnessPlanVO(fitnessPlan);

    }

}
